extends Node
var utils

#进入战斗界面：sys.batScene.connect("onBattleReady",self,xxx)
#进入游戏绑定角色移动：sys.game.connect("onNewGame",self,xxx) -> sys.game.$ui/home.get_tree().connect("node_added", self, "on_node_added")->add context->connect("onChaMove",self,xxx)
#神徽：sys.game.$ui/home.get_tree().connect("node_added", self, "on_node_added")->add context；sys.player.relics.connect("onAddItem",self,xxx)
#装备：sys.connect("node_added", self, "on_node_added")->update context&add context;chas.eqps.connect("onAddItem",self,xxx,)chas.eqps.connect("onDelItem",self,xxx)

# 储存mod各自羁绊设定,储存格式：
#｛
# 	羁绊id:{
# 	"cnt":[触发个数数组],
#   "name":羁绊名,
#	"text":羁绊描述文本,
# 	"ico":羁绊图片路径,
#   "script":羁绊实例,
#   "func":触发加减函数名}
# ｝
# all模式：以trait中实例个数去算cnt阶段
# solo模式:以solocal中羁绊id中keys个数去算cnt阶段
# macth模式：必须与cnt阶段的数字完全一样，不然不触发
var eqpcontext = VBoxContainer.new()
var reliccontext = VBoxContainer.new()
var chacontext = VBoxContainer.new()
var dynamic_font = DynamicFont.new()
#储存羁绊Json设置
var settings = {}
#储存羁绊,储存格式：｛羁绊id：【实例】｝，eqp则为｛羁绊id：｛角色实例：【装备实例】｝｝
var trait={
	"relic":{},
	"eqp":{},
	"tab":{},
}
# 独立计算羁绊使用（即名字重复单独算计数1），储存格式 羁绊id：{物体id:个数},装备、神徽羁绊默认SOLO
var solocal={}
# 贴合触发（即有且只有上场了对应个数时触发），储存格式 羁绊id,装备、神徽羁绊默认Match
var matchtrait=[]
# 羁绊阶段｛羁绊id：0/1/2/3/4｝,装备为：｛羁绊id：｛角色实例：0/1/2/3}}
var stage={}
# 羁绊计数储存｛羁绊id：个数｝,装备为：｛羁绊id：｛角色实例：个数}}
var traitcnt = {}
# 角色是否上场战斗
var chaBattle = {}
# 当前羁绊描述
var keytext = {}
#判断是否继续遍历进文件夹
func check(dname):
	return dname != "core" && dname !="." && dname !=".." && dname.find("ex") == -1 && dname !="res" && dname !="sdk" && dname !="tscn" 
#根据json初始化
func initSettings(dict):
	if !dict || !dict.keys():return
	for one in dict.keys():
		var type = dict[one].get("type","")
		if type == "eqp":
			trait["eqp"][one] = {}
			stage[one] = {}
		elif type == "relic":
			trait["relic"][one]=[]
			matchtrait.push_back(one)
			solocal[one]={}
			stage[one]=0
		elif type == "tab":
			trait["tab"][one]=[]
			var mode = dict[one].get("mode","")
			if mode.find("solo") != -1:
				solocal[one]={}
			if mode.find("match") != -1:
				matchtrait.push_back(one)
			stage[one]=0
		else:
			print(one,"  羁绊设置错误  ")
			continue
		# var newdict = {}
		settings[one]=dict[one]
		settings[one]["cnt"]=dict[one].get("cnt",[])
		settings[one]["text"]=dict[one].get("text","")
		settings[one]["ico"]=dict[one].get("ico","")
		settings[one]["script"]=dict[one].get("script","")
		settings[one]["func"]=dict[one].get("func","")
		settings[one]["name"]=dict[one].get("name","")
#加载Json
func loadJson(dirStr):
	var dir = Directory.new()
	dir.open(dirStr)
	dir.list_dir_begin()
	var dname = dir.get_next()
	while dname != "":
		if dir.current_is_dir() && check(dname):
			loadJson(dirStr + "/" + dname)
		elif !dir.current_is_dir() && dname == "trait_setting.json":
			var file = File.new()
			file.open(dir.get_current_dir() + "/" + dname,file.READ)
			var dic = parse_json(file.get_as_text())
			initSettings(dic)
		dname = dir.get_next()
	dir.list_dir_end()
# 读取json初始化
func _ready():
	utils = sys.get_node("VEBase").utils
	loadJson("res://")
	sys.main.get_tree().connect("node_added",self,"connectAll")
	dynamic_font.font_data = load("res://!ve/base/1.ttf")
	dynamic_font.size = 10
	print("VEBaseTrait ready")
	pass 
# game初始化后链接信号
func connectAll(node):
	if node.name != "game":
		return
	yield(get_tree().create_timer(0.03),"timeout")

	chacontext = null
	upAll()
	# ui链接信号
	sys.game.connect("onBattleReady",self,"addChaContext")
	nodeconnect()
	# 羁绊实例更新信号
	sys.game.connect("onChaFire",self,"delCha")
	sys.player.connect("onAddAlterCha",self,"addCha")
#	sys.player.relics.connect("onAddItem",self,"addRelic")
#	sys.get_tree().connect("node_added",self,"on_node_add")
	print("Trait Connect Success")
## 增加装备
#func addItem(item,idx):
#	_addTrait(item,"eqp")
## 删除装备
#func delItem(item,idx):
#	_addTrait(item,"eqp",false)
## 增加神徽
#func addRelic(item,idx):
#	_addTrait(item,"relic")
# 增加角色
func addCha(cha):
	chaBattle[cha] = false
# 删除角色
func delCha(cha):
	if chaBattle.has(cha):
		chaBattle.erase(cha)
# 中转链接
func nodeconnect():
	var home = sys.game.get_node_or_null("ui/home")
	if home:
		home.get_tree().connect("node_added",self,"DlgAdd")
# charaDlg 检测
#func on_node_add(node):
#	if node.name == "charaDlg":
#		yield(get_tree().create_timer(0.03),"timeout")	
#		node.cha.eqps.connect("onAddItem",self,"addItem")
#		node.cha.eqps.connect("onDelItem",self,"delItem")
#		node.connect("onDel",self,"chadisconnect",[node.cha])
#		for one in node.cha.eqps.items:
#			if one:	_addTrait(one,"eqp")
#		if !node.get_node_or_null("Container"):
#			if not is_instance_valid(eqpcontext):eqpcontext = VBoxContainer.new()
#			node.add_child(eqpcontext)
#			addText(eqpcontext)
#			node.connect('onDel',self,"remove_context",[node,chacontext])
# 战队调整窗口或神徽窗口弹出
func DlgAdd(node):
	if node.name == "Popup":
		if !node.get_node_or_null('m') && !node.get_node_or_null('jtip'):
			return
		if sys.game.mode == "towerEx":
			yield(get_tree().create_timer(0.4),"timeout")
		node.get_node('batScene').connect("onChaMove",self,"ChaMove")
		if !node.get_node_or_null("VBoxContainer"):
			node.add_child(chacontext)
			addText(chacontext)
			node.connect('onDel',self,"remove_context",[node,chacontext])
			if sys.game.diffLv == 0 && getJtip() == 0:
				chacontext.set_position(Vector2(230,38))
			else:
				chacontext.set_position(Vector2(230,13))
				
			if sys.game.mode == "towerEx":
				chacontext.set_position(Vector2(170,105))
#	if node.name == "relicDlg":
#		if !node.get_node_or_null("VBoxContainer"):
#			node.add_child(reliccontext)
#			addText(reliccontext)
#			node.connect('onDel',self,"remove_context",[node,reliccontext])
			
#获取提示文本		
func getJtip():
	if sys.game.globals.has("g_game"):
		return sys.game.globals.g_game.jtip
	elif sys.game.globals.has("g_tGame"):
		return sys.game.globals.g_tGame.jtip
	elif sys.game.globals.has("g_gameTower"):
		return sys.game.globals.g_gameTower.jtip				
# 角色移动，判断上下场
func ChaMove():
	for one in sys.player.team.chas:
		# 当前下场，上次在场
		if one.cell.x >= 5 and chaBattle[one]:
			chaBattle[one] = false
			_addTrait(one,"tab",false)
		# 当前在场，上次下场
		elif one.cell.x < 5 and !chaBattle[one]:
			chaBattle[one] = true
			_addTrait(one,"tab")
# 添加职业羁绊表现//OK
func addChaContext():
	var fa = sys.batScene.get_parent()
	if fa.name == "batDlg":
		fa = fa.get_node("ui")
		if !fa.get_node_or_null("Container"):
			fa.add_child(chacontext)
			addText(chacontext)
			fa.connect("tree_exited",self,"remove_context",[fa,chacontext])
			#fa.connect('onDel',self,"remove_context",[fa,chacontext])
			chacontext.set_position(Vector2(79,11))
# ui挂载
func uiUp_fa(key,text,ico,val,cnt,fa):
	var row = fa.get_node_or_null(key)
	if not row:
		row = HBoxContainer.new()
		row.name = key
		row.add_child(ico)
		row.add_child(Label.new())
		fa.add_child(row)
	var nowcnt = traitcnt[key][val] if val else traitcnt[key] 
	if !nowcnt:
		sys.main.delTip(row)
		fa.remove_child(row)
		return
	else:
		addTip(row,text)
	var nxtcnt = -1
	for i in settings[key]["cnt"]:
		if i > nowcnt:
			nxtcnt = i
			break
	if nxtcnt == -1:nxtcnt = settings[key]["cnt"][-1]		
	var lb = row.get_child(1)
	lb.text = "( " + str(nowcnt) + " / " + str(nxtcnt) + " )"
	lb.set("custom_fonts/font", dynamic_font)
	if cnt:
		lb.add_color_override("font_color", Color("#ffd700"))
	else:
		lb.add_color_override("font_color", Color(1,1,1,1))
# ui布局更新
func uiUp(key,cnt,type,val):
	var tmptext = "[color=#ffffff][center]%s[/center]\n%s" % [settings[key]["name"],settings[key]["text"]]
	var text = ""
	if cnt:
		var pos = -3
		var flag1 = 0
		var flag2 = 0
		for i in tmptext:
			if i == "[":
				pos += 1
			if pos == cnt && !flag1 :
				text += "[b][color=#ffd700]["
				flag1 = 1
				continue
			if pos == cnt + 1 && !flag2:
				flag2 = 1
				text += "[/color][/b]["
				continue
			text += i
		if !flag2:
			text += "[/color][/b]"
		text += "[/color]"
	else:
		text = tmptext
	keytext[key] = text
	var ico_path = settings[key]["ico"]
	var ico = null
	if ico_path:
		ico = utils.createTextureRect(ico_path)
		ico.rect_size = Vector2(21,21)
		ico.expand = true
	else:
		ico = Label.new()
		ico.text = settings[key]["name"]
		ico.set("custom_fonts/font", dynamic_font)
	if type == "eqp":
		uiUp_fa(key,text,ico,val,cnt,eqpcontext)
	elif type == "relic":
		uiUp_fa(key,text,ico,null,cnt,reliccontext)
	elif type == "tab":
		uiUp_fa(key,text,ico,null,cnt,chacontext.get_child(1))	
# 触发阶段切换
var scriptCache = {}
func _trigger(key,val,cnt,type,isUp):
	var script = settings[key].get("script",null)
	var funname = settings[key].get("func","_trigger")
	if typeof(script) == TYPE_STRING:
		if scriptCache.has(script):
			script = scriptCache.get(script)
		else:
			var newScript = load(data.infoDs[script][script].dir).new()
			settings[key]["script"]=newScript
			scriptCache[script] = newScript
			script = newScript
	if not script.has_method(funname):return
	script.callv(funname,[key,cnt,isUp,settings[key],val])
# 更新检索是否触发羁绊阶段切换
func up(val,key,type,isSolo):
	if key == "" or not settings.has(key):return
	var isMatch = key in matchtrait
	var passstage = stage.get(key,0)
	var nowstage = passstage
	var nowcnt = traitcnt[key]
	var pos = 0
	if isMatch:
		pos = settings.get(key).get("cnt").find(float(nowcnt))
		nowstage = pos + 1
	else:
		for i in settings.get(key).get("cnt"):
			if nowcnt >= i:
				pos += 1
				continue
			break
		nowstage = pos
	uiUp(key,nowstage,type,val)
	if nowstage != passstage:
		stage[key]=nowstage
		_trigger(key,val,nowstage,type,nowstage > passstage)
# 人物羁绊是否为最大solo才有用
func isMaxCnt(cha,chalist,key):
	if not chalist:
		return [true,0,false]
	var maxcha = chalist[0]
	var maxcnt = [-1,-1]
	var mincnt = 100000
	for i in chalist:
		var keys = i.trait.split(" ") if i.get("trait") else i.tab.split(" ")
		var cnts = i.traitcnt if i.get("traitcnt") else []
		var pos = keys.find(key)
		var nowcnt = cnts[pos] if cnts.size() > pos && pos > 0 else 1
		if maxcnt[1] <= nowcnt:
			maxcnt[0] = maxcnt[1]
			maxcnt[1] = nowcnt
			maxcha = i
		elif maxcnt[0] < nowcnt:
			maxcnt[0] = nowcnt
		mincnt = min(mincnt,nowcnt)
	if maxcnt[0] == -1:maxcnt[0] = maxcnt[1]
	return [maxcha == cha,maxcnt[1] - maxcnt[0],mincnt == maxcnt[1]]
# 人物羁绊增减ex
func addTraitHero_ex(cha,type,key,keycnt,isAdd,isSolo):
	if not settings.has(key):return
	var solocnt = 0
	if isSolo:
		solocnt = solocal[key].get(cha.id,0)
	var chalist = trait[type].get(key,[])
##
#	for i in range(chalist.size()-1, -1, -1):
#		var c = chalist[i]
#		if c.isDel:
#			chalist.remove(i)
#
#	trait[type][key] = chalist
#
#	for i in chalist:
#		if i.id == cha.id:
#			solocnt += 1
#	solocal[key][cha.id] = solocnt
	
	if isAdd and chalist.has(cha):
		return
	if not chalist and not isAdd:
		return

	var cnt = traitcnt.get(key,0)
	if not isAdd:
		chalist.erase(cha)
		solocnt -= 1
		keycnt *= -1
	else:
		chalist.push_back(cha)
	if isSolo:
		var flag = isMaxCnt(cha,chalist,key)
		if flag[0] && not flag[2]:
			traitcnt[key] += flag[1] if isAdd else (-1*flag[1])
		if not solocnt:
			traitcnt[key] = cnt + keycnt
		if isAdd:solocnt += 1
		solocal[key][cha.id] = max(solocnt,0)
		return
	traitcnt[key] = cnt + keycnt	
# 人物羁绊增减
func addTraitHero(cha,isAdd):
	var tabs = cha.trait.split(" ") if cha.get("trait") else cha.tab.split(" ")
	var cnts = cha.traitcnt  if cha.get("traitcnt") else []
	if cnts.empty():
		for i in tabs:
			cnts.append(1)
	var pos = 0
	for one in tabs:
		var isSolo = solocal.has(one)
		addTraitHero_ex(cha,"tab",one,cnts[pos],isAdd,isSolo)
		up(cha,one,"tab",isSolo)
		pos += 1
# 装备羁绊增减
#func addTraitEqp(item,isAdd):
#	var tabs = item.trait.split(" ") if item.get("trait") else item.tab.split(" ")
#	var cnts = item.traitcnt if item.get("trait") else []
#	if cnts.empty():
#		for i in tabs:
#			cnts.push_back(1)
#	var name = item.id
#	var masCha = item.wearer
#	var cntpos = -1
#	for one in tabs:
#		cntpos += 1
#		var itemslist =trait["eqp"][one].get(masCha,[])
#		if not isAdd && not itemslist:
#			continue
#		if not isAdd:
#			itemslist.erase(item)
#		else:
#			itemslist.push_back(item)
#		var stagedict= stage.get(one,{})
#		if not stagedict:
#			stagedict = {masCha:0}
#			stage[one] = stagedict
#		var passstage = stagedict.get(masCha)
#		var nowcnt = 0
#		var tmplist = [name]
#		for i in itemslist:
#			if i.id in tmplist:continue
#			else:tmplist.push_back(i.id)
#			if i.get('trait',"  ").find(one) != -1:
#				nowcnt += cnts[cntpos]
#		var pos = 0
#		pos = settings[one]["cnt"].find(nowcnt)
#		var nowstage = pos + 1
#		if nowstage != passstage:
#			stagedict[masCha]=nowstage
#			stage[one]=stagedict
#			_trigger(one,item.wearer,nowstage,"item",nowstage > passstage)
## 神徽羁绊增减
#func addTraitRelic(relic,isAdd):
#	var tabs = relic.trait.split(" ") if relic.get("trait") else relic.tab.split(" ")
#	var cnts = relic.traitcnt if relic.get("traitcnt") else []
#	if cnts.empty():
#		for i in tabs:
#			cnts.push_back(1)
#	var name = relic.id
#	var pos = 0
#	for one in tabs:
#		var reliclist = trait["relic"].get(one,[])
#		if relic in reliclist:
#			pos+=1
#			continue
#		reliclist.push_back(relic)
#		solocal[one]={name:1}
#		var cnt = traitcnt.get(one,0)
#		cnt += cnts[pos]
#		traitcnt[one]=cnt
#		pos += 1
#		up(relic,one,"relic",true)
# 触发增减羁绊
func _addTrait(val,type,isAdd = true):
	if val == null or val.get("trait") == null or val.get("traitcnt") == null:
		return
	if type == "tab":
		addTraitHero(val,isAdd)
#	elif type == "eqp":
#		addTraitEqp(val,isAdd)
#	elif type == "relic":
#		addTraitRelic(val,isAdd)
# 角色详情关闭，删除信号链接
func chadisconnect(cha):
	cha.eqps.disconnect("onAddItem",self,"addItem")
	cha.eqps.disconnect("onDelItem",self,"delItem")
# 把context从UI中移除，避免被释放
func remove_context(fa,kid):
	fa.remove_child(kid)
	for i in kid.get_children():
		if i is Button:
			i.disconnect('pressed',sys.main,'_btnPressed')
# 继续游戏时刷新relic和cha context
func upAll():
	var cnt = sys.player.team.chas.size()
#	if !cnt or sys.game.mode == "towerEx":
	initData()
	chaBattle = {}
	for one in sys.player.team.chas:
		chaBattle[one] = one.cell.x < 5
		
	if chacontext != null and cnt && chacontext.get_child_count(): 
		return
	chacontext = VBoxContainer.new()
	var btn = Button.new()
	btn.name = 'upBtn'
	btn.text = '收起羁绊显示'
	btn.set("custom_fonts/font", dynamic_font)
	chacontext.add_child(btn)
	var vbox = VBoxContainer.new()
	vbox.name = 'vbox'
	chacontext.add_child(vbox)
	btn.connect("pressed",self,"switchVbox",[vbox,btn])
#	reliccontext = VBoxContainer.new()
#	if sys.game.mode != "towerEx":
	for one in sys.player.team.chas:
		if chaBattle[one]:
			_addTrait(one,"tab")
#	for one in sys.player.relics.items:
#		_addTrait(one,"relic")
# 初始化数据
func initData():
	for i in trait.keys():
		for j in trait[i].keys():
			if i != 'eqp':
				trait[i][j]=[]
			else:trait[i][j]={}
	for i in solocal.keys():
		solocal[i]={}
	for i in stage.keys():
		if typeof(stage[i]) == TYPE_INT:
			stage[i]=0
		else:stage[i]={}
	for i in traitcnt.keys():
		if typeof(traitcnt[i]) == TYPE_INT:
			traitcnt[i] = 0
		else:traitcnt[i] = {}
	chaBattle = {}
# 重新添加提示
func addText(context):
	if not is_instance_valid(context):
		upAll()
		return
	if context.get_child(0) is Button:
		context = context.get_child(1)
	for i in context.get_children():
		addTip(i,keytext[i.name])
# 收起/展开容器
func switchVbox(vbox,btn):
	vbox.visible = !vbox.visible
	btn.text = "收起羁绊显示" if vbox.visible else "展开羁绊显示"
	chacontext.mouse_filter = int(!chacontext.mouse_filter)

func addTip(node:Control,txt):
	if sys.main.tipDs.has(node) == false :
		sys.main.tipDs[node] = txt
	else:
		sys.main.tipDs[node] = txt
		if sys.main.tip.visible && sys.main.sNode == node: 
			self.txt.bbcode_text = sys.main.tipDs[node]
		return
	if is_instance_valid(node) == false: return
	if not node.is_connected("mouse_entered", sys.main, "showTip"):
		node.connect("mouse_entered",sys.main,"showTip",[node])
		node.connect("mouse_exited",sys.main,"hideTip")
		node.connect("visibility_changed",sys.main,"hideTip")
		node.connect("tree_exiting",sys.main,"delTip",[node])
